Skip to content

feat: agent execution resilience - file conflicts, verification recovery, observability - #342

Merged
frankbria merged 2 commits into
mainfrom
feature/agent-execution-resilience
Feb 7, 2026
Merged

feat: agent execution resilience - file conflicts, verification recovery, observability#342
frankbria merged 2 commits into
mainfrom
feature/agent-execution-resilience

Conversation

@frankbria

@frankbria frankbria commented Feb 7, 2026

Copy link
Copy Markdown
Owner

Summary

Improves agent execution reliability with three targeted enhancements:

  • File conflict handling: file_create now falls back to edit when a file already exists (instead of failing), and the planner prompt warns the LLM about existing files to guide correct operation choice
  • Verification recovery: Separate tracking of verification failures vs step failures, with early abort after 3 consecutive verification failures. Incremental verification now captures full ruff output for better self-correction context
  • Observability: Structured ruff error parsing into {file, line, col, code, message} dicts, new GateResult.get_error_summary() and get_errors_by_file() methods, and enriched verification_failed SSE events with gate names, error counts, and details

Test plan

  • 15 new TDD tests across 4 test files
  • 1003/1003 core tests pass (0 regressions)
  • Ruff lint: all checks passed
  • Verify file conflict fallback works in real agent execution
  • Verify early abort creates blocker with useful context
  • Verify SSE events display enriched verification errors in Execution Monitor

Summary by CodeRabbit

  • New Features

    • Richer lint/error reporting surfaced with file locations, codes, and grouped summaries.
    • Planner prompt now warns about existing files and suggests using edits instead of creates.
  • Bug Fixes

    • File creation falls back to editing when a file already exists; identical content is treated as no-op.
    • Verification now tracks consecutive verification failures and aborts after repeated failures, emitting richer failure details and creating blockers when needed.
  • Tests

    • Expanded tests for verification recovery, file conflict handling, and error parsing.

…on recovery, observability

Three improvements to agent execution reliability:

1. File conflict handling (executor + planner):
   - file_create now falls back to edit when file exists with different content
   - Returns no-op success when file exists with identical content
   - Planner prompt warns about existing files to guide LLM toward file_edit

2. Verification recovery (agent):
   - Separate tracking of verification failures vs step execution failures
   - Early abort after MAX_CONSECUTIVE_VERIFICATION_FAILURES (3) with blocker
   - Incremental verification now captures full ruff output (verbose=True)
     for better self-correction context
   - Enhanced error details passed to self-correction attempts

3. Observability (gates + events):
   - Structured ruff error parsing into {file, line, col, code, message} dicts
   - GateCheck.detailed_errors field for programmatic access
   - GateResult.get_error_summary() and get_errors_by_file() methods
   - verification_failed events now include gate names, error count, and details

Tests: 15 new tests (TDD), 1003/1003 core tests pass, 0 regressions.
@coderabbitai

coderabbitai Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Enhances verification failure handling with an abort threshold and richer failure payloads, adds Ruff error parsing and observability, makes file_create gracefully fall back to edit when files exist, augments planner prompts with existing-files guidance, and adds tests covering these behaviors.

Changes

Cohort / File(s) Summary
Verification Failure Tracking & Abort
codeframe/core/agent.py
Adds public MAX_CONSECUTIVE_VERIFICATION_FAILURES = 3, tracks consecutive_verification_failures separately, enriches verification_failed events with error_names, error_count, and truncated error_details, runs incremental verification with verbose=True, and aborts (creates blocker, emits execution_aborted, sets state BLOCKED) after threshold reached.
File Creation Fallback
codeframe/core/executor.py
Changes _execute_file_create to detect existing files: if identical content → return SUCCESS (no-op); if different and dry_run → return SUCCESS with dry-run message; otherwise write new content, record an edit FileChange, and return SUCCESS instead of failing.
Error Parsing & Observability
codeframe/core/gates.py
Adds _RUFF_ERROR_PATTERN and _parse_ruff_errors to parse Ruff output into structured errors; adds detailed_errors to GateCheck/GateResult; adds get_error_summary and get_errors_by_file helpers; populates detailed_errors when Ruff fails.
Planning Guidance
codeframe/core/planner.py
Updates planner prompt (_build_prompt) to include an "Existing Files Warning" section listing up to 50 existing workspace file paths and instructing use of file_edit for those files.
Verification Recovery Tests
tests/core/test_agent.py
Adds TestVerificationRecovery verifying presence/value of MAX_CONSECUTIVE_VERIFICATION_FAILURES, that _execute_plan tracks consecutive_verification_failures, that verification_failed payload includes enriched fields, that _run_incremental_verification uses verbose=True, and abort/blocker behaviors are exercised.
File Operation Fallback Tests
tests/core/test_executor.py
Renames and adds tests in TestFileCreateConflictHandling to validate fallback-to-edit behavior when files exist with differing content, success no-op when identical content, and dry-run behavior preserving original content.
Gate Observability Tests
tests/core/test_gates_observability.py
Adds tests for _parse_ruff_errors (single/multiple/mixed/empty outputs), GateCheck.detailed_errors presence/default, GateResult error summary formatting and grouping, and handling when no errors exist.
Planning Context Tests & Types
tests/core/test_planner.py, codeframe/core/context
Adds FileInfo(path, size_bytes, extension) usage in tests and TestPlannerExistingFilesContext to assert planner prompt includes Existing Files section and recommends file_edit operations.

Sequence Diagram(s)

sequenceDiagram
    participant Agent
    participant PlanExecutor
    participant GateChecks
    participant Blocker

    Agent->>PlanExecutor: execute_plan()
    PlanExecutor->>PlanExecutor: init consecutive_verification_failures = 0
    loop plan steps
        PlanExecutor->>GateChecks: run incremental verification (verbose=True)
        alt passed
            GateChecks-->>PlanExecutor: gate_result.passed = true
            PlanExecutor->>PlanExecutor: consecutive_verification_failures = 0
        else failed
            GateChecks-->>PlanExecutor: gate_result.passed = false, detailed_errors[]
            PlanExecutor->>PlanExecutor: consecutive_verification_failures += 1
            PlanExecutor->>Agent: emit verification_failed (error_names, error_count, error_details)
            alt consecutive_verification_failures >= MAX_CONSECUTIVE_VERIFICATION_FAILURES
                PlanExecutor->>Blocker: create_blocker(with failure context)
                PlanExecutor->>Agent: emit execution_aborted
                PlanExecutor-->>Agent: abort execution
            else
                PlanExecutor->>PlanExecutor: attempt self-correction and continue
            end
        end
    end
Loading
sequenceDiagram
    participant Executor
    participant FileSystem
    participant LLM
    participant Storage

    Executor->>FileSystem: check if file exists (path)
    alt file does not exist
        Executor->>FileSystem: write new file (create)
        Executor->>Storage: record FileChange (create)
        Executor-->>Executor: return SUCCESS
    else file exists
        Executor->>FileSystem: read existing content
        alt content identical
            Executor-->>Executor: return SUCCESS (no-op)
        else content differs
            alt dry_run
                Executor-->>Executor: return SUCCESS (dry-run message)
            else normal
                Executor->>LLM: generate/confirm new content
                LLM-->>Executor: updated content
                Executor->>FileSystem: write updated content (edit)
                Executor->>Storage: record FileChange (edit, old_content)
                Executor-->>Executor: return SUCCESS
            end
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through gates with careful eyes,
Counting failures, three's the surprise,
Creates that clash now gracefully mend,
Ruff's errors parsed from end to end—
A tidy burrow for code to rise!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the three main areas of change: file conflicts, verification recovery, and observability improvements.
Docstring Coverage ✅ Passed Docstring coverage is 95.12% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/agent-execution-resilience

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude

claude Bot commented Feb 7, 2026

Copy link
Copy Markdown

Code Review - PR #342: Agent Execution Resilience

I've reviewed the changes for agent execution resilience improvements. Overall, this is a well-designed enhancement that addresses real pain points in agent execution.

Strengths

  1. Excellent separation of concerns: Tracking verification failures separately from step execution failures is the right architectural choice.

  2. Strong test coverage: 15 new tests across 4 files with good coverage of edge cases.

  3. Observability improvements: The structured ruff error parsing and enriched SSE events will significantly improve debugging.

  4. Graceful fallback in file_create: The fallback from file_create to file_edit when files exist is pragmatic.

Code Quality Observations

1. Ruff Error Parsing (gates.py:27)
The regex pattern may not handle Windows paths with drive letters or ruff JSON output format. Consider adding a test case for Windows paths.

2. Error Detail Truncation (agent.py:641, 654)
Two different limits: 500 chars per check, 1000 total. If multiple checks fail, you could exceed 1000 before final truncation. Document this behavior.

3. consecutive_verification_failures Reset (agent.py:695)
Counter resets on success but only increments on self-correction failure. Verify in integration testing that the 3-failure threshold works across multiple file operations.

4. File Content Comparison (executor.py:302)
The strip() comparison ignores whitespace differences. Consider logging when comparison succeeds but raw content differs.

Missing Test Coverage

  1. Integration test for early abort (3 consecutive verification failures)
  2. Windows path handling in _parse_ruff_errors
  3. Error handling when _generate_file_content fails during fallback

Recommendations

High Priority:

  • Add integration test for early abort scenario
  • Add error handling in executor.py:_execute_file_create for _generate_file_content failures

Medium Priority:

  • Document truncation strategy
  • Add test for Windows paths or document Unix-only assumption

Low Priority:

  • Log when file content matches after strip but differs in raw form

Summary

This is high-quality work following the repository's principles. Recommendation: Approve with minor suggestions. The high-priority items should be addressed before merge.

Comment thread codeframe/core/gates.py Outdated
@macroscopeapp

macroscopeapp Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor

Abort agent execution after 3 consecutive verification failures, emit structured verification events, and treat Executor._execute_file_create on existing files as edit or no-op

Add a verification failure counter and blocker creation in Agent._execute_plan; emit structured verification_failed and execution_aborted events; parse ruff errors into structured data in gates; update planning prompt to warn against file_create on existing files; and make Executor._execute_file_create update or no-op when the target already exists. Key changes span codeframe/core/agent.py, codeframe/core/executor.py, codeframe/core/gates.py, and codeframe/core/planner.py.

📍Where to Start

Start with Agent._execute_plan in codeframe/core/agent.py, then review Executor._execute_file_create in codeframe/core/executor.py and gate parsing in codeframe/core/gates.py.


Macroscope summarized 2412bbc.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
codeframe/core/agent.py (1)

622-625: ⚠️ Potential issue | 🟠 Major

Reset consecutive verification failures after a successful incremental verification.
Right now the counter only resets on self-correction success, so a later clean verification still leaves the counter > 0 and can trigger a premature abort.

✅ Suggested fix
-                    if gate_result and not gate_result.passed:
+                    if gate_result and gate_result.passed:
+                        consecutive_verification_failures = 0
+                    elif gate_result and not gate_result.passed:
                         # Try to fix lint issues automatically (works for style, not syntax)
🤖 Fix all issues with AI agents
In `@codeframe/core/agent.py`:
- Around line 700-711: The early-abort path checks
consecutive_verification_failures and calls
self._create_blocker_from_failure(step, current_result) but that helper can
return without creating a blocker, leaving the step in EXECUTING; ensure a
blocker is always created on this abort: call _create_blocker_from_failure and
if it returns a falsy/None value then explicitly create or mark the blocker
(e.g. call a guaranteed blocker creation routine or set the step/state to
BLOCKED and emit the "execution_aborted" event) so that the abort always forces
an actual blocker regardless of TECHNICAL_FIX/RESOLVE_AUTONOMOUSLY paths;
reference the symbols consecutive_verification_failures,
MAX_CONSECUTIVE_VERIFICATION_FAILURES, self._create_blocker_from_failure(step,
current_result), self._emit_event("execution_aborted", ...), and step to
implement the check-and-force behavior.

In `@codeframe/core/gates.py`:
- Around line 121-151: Update the GATES_COMPLETED event payload to include the
structured diagnostics produced by get_error_summary() and get_errors_by_file(),
and add a "suggestions" field per gate (e.g., suggested fixes or actionable
hints); specifically, when emitting the GATES_COMPLETED event for each Gate
instance (use the existing checks list / Gate object), call get_error_summary()
and get_errors_by_file() and include their outputs as "error_summary" (string)
and "errors_by_file" (dict) in the payload along with the existing gate name and
pass/fail status, and add a "suggestions" array populated from any
Check.suggestions or a synthesized suggestion list so consumers can display
remediation steps.
- Around line 27-51: The regex _RUFF_ERROR_PATTERN used by _parse_ruff_errors
only allows a single uppercase letter before the digits and thus drops
multi-letter rule codes like ANN401 or PLR2004; update the pattern to accept one
or more uppercase letters before the digits (e.g. change ([A-Z]\d+) to
([A-Z]+\d+)) so _parse_ruff_errors will correctly capture multi-letter rule
codes while keeping the same capture groups for file, line, col, code, and
message.

Comment thread codeframe/core/agent.py
Comment thread codeframe/core/gates.py Outdated
Comment thread codeframe/core/gates.py
Comment on lines +121 to +151
def get_error_summary(self) -> str:
"""Format all errors into a readable multi-line string.

Returns:
Newline-separated string of all structured errors from failed checks,
or empty string if no errors.
"""
lines = []
for check in self.checks:
if check.detailed_errors:
for err in check.detailed_errors:
lines.append(
f"{err['file']}:{err['line']}:{err['col']}: "
f"{err['code']} {err['message']}"
)
return "\n".join(lines)

def get_errors_by_file(self) -> dict[str, list[str]]:
"""Group error messages by file path.

Returns:
Dict mapping file paths to lists of formatted error strings.
"""
by_file: dict[str, list[str]] = {}
for check in self.checks:
if check.detailed_errors:
for err in check.detailed_errors:
file_path = err["file"]
msg = f"{err['code']} {err['message']} (line {err['line']})"
by_file.setdefault(file_path, []).append(msg)
return by_file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Emit structured gate error details in the GATES_COMPLETED event.
You already added get_error_summary() / get_errors_by_file(); surfacing those (and a suggestions field) in the gate completion payload is required for diagnostics.

✅ Suggested fix
-    events.emit_for_workspace(
-        workspace,
-        events.EventType.GATES_COMPLETED,
-        {
-            "passed": passed,
-            "summary": result.summary,
-            "checks": [{"name": c.name, "status": c.status.value} for c in checks],
-        },
-        print_event=True,
-    )
+    payload = {
+        "passed": passed,
+        "summary": result.summary,
+        "checks": [{"name": c.name, "status": c.status.value} for c in checks],
+    }
+    if not passed:
+        payload["error_summary"] = result.get_error_summary()
+        payload["errors_by_file"] = result.get_errors_by_file()
+        payload["suggestions"] = []  # populate when available
+
+    events.emit_for_workspace(
+        workspace,
+        events.EventType.GATES_COMPLETED,
+        payload,
+        print_event=True,
+    )

As per coding guidelines: "Modules handling verification gates (ruff, pytest, BUILD checks) must emit detailed diagnostic events including gate name, passed/failed status, error messages, and suggestions for fixes."

🤖 Prompt for AI Agents
In `@codeframe/core/gates.py` around lines 121 - 151, Update the GATES_COMPLETED
event payload to include the structured diagnostics produced by
get_error_summary() and get_errors_by_file(), and add a "suggestions" field per
gate (e.g., suggested fixes or actionable hints); specifically, when emitting
the GATES_COMPLETED event for each Gate instance (use the existing checks list /
Gate object), call get_error_summary() and get_errors_by_file() and include
their outputs as "error_summary" (string) and "errors_by_file" (dict) in the
payload along with the existing gate name and pass/fail status, and add a
"suggestions" array populated from any Check.suggestions or a synthesized
suggestion list so consumers can display remediation steps.

…etter ruff codes

Three fixes from code review:

1. Reset consecutive_verification_failures on clean verification pass,
   not just on self-correction success. Prevents premature abort after
   fail → pass → fail → fail sequences.

2. Abort path now calls blockers.create directly instead of
   _create_blocker_from_failure, which could silently return for
   RESOLVE_AUTONOMOUSLY/TECHNICAL_FIX classifications. Abort must
   always produce a blocker.

3. Ruff error regex now accepts multi-letter rule codes (ANN401, PLR2004,
   SIM118, UP035) by changing [A-Z] to [A-Z]+.

Declined: enriching GATES_COMPLETED event payload with structured diagnostics
and suggestions field — YAGNI, the methods exist for programmatic access.
@claude

claude Bot commented Feb 7, 2026

Copy link
Copy Markdown

Updated Code Review - PR #342

I've reviewed the changes again. This is a solid improvement to agent execution resilience. My previous review covered the main points, and I see CodeRabbit has also provided detailed feedback. Here are some additional observations:

Critical Issue from CodeRabbit Review

Regex Pattern for Multi-Letter Rule Codes (gates.py:218)

CodeRabbit correctly identified that the regex pattern only matches single-letter prefixes. This will fail for common ruff rules like ANN401, PLR2004, SIM118, and UP035.

Fix needed: Change [A-Z]\d+ to [A-Z]+\d+ in the regex pattern on line 218.

I notice there's already a test for this in test_gates_observability.py:605 which is excellent - but the regex needs to be updated to make that test pass.

Additional Observations

1. Verification Counter Reset (agent.py:625-627)

Good - the counter now properly resets on successful verification. This prevents the scenario: fail → pass → fail → fail from incorrectly triggering abort.

2. Error Detail Truncation Consistency

The truncation strategy has two levels:

  • Line 644: check.output[:500] per check
  • Line 658: error_detail_str[:1000] total

This is reasonable but worth documenting in code comments.

3. File Conflict Fallback (executor.py:302)

The .strip() comparison for content identity is pragmatic but could hide meaningful whitespace differences. Consider adding a verbose log when strip() matches but raw content differs.

4. Early Abort Path (agent.py:701-711)

The forced blocker creation bypassing LLM classification is the right approach. This ensures we always get a blocker on abort, not a silent RESOLVE_AUTONOMOUSLY classification.

Test Coverage Assessment

Strong test coverage with 15 new tests. The tests use both integration-style checks and source inspection, which is appropriate for TDD verification. All high-priority scenarios are covered.

Recommendations Priority

Must fix before merge:

  1. Fix regex pattern for multi-letter ruff codes (gates.py:218)

Should consider:
2. Add verbose logging for stripped vs raw content differences in file_create fallback
3. Document truncation strategy in code comments

Nice to have:
4. Integration test for the full early-abort flow (currently uses source inspection)

Summary

This PR delivers meaningful improvements to agent reliability. The regex bug is the only blocking issue. Once fixed, this is ready to merge.

Excellent work on the separation of concerns between verification failures and step execution failures - this architectural choice will pay dividends.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Phase 1] Improve agent execution resilience: file conflicts and verification recovery

1 participant